<#assign object = doc.object>
package ${object.package}.model.base;

<#if object.attributes.xml[0]??>
import ${object.package}.model.xml.*;
import org.apache.commons.lang.builder.HashCodeBuilder;
</#if>
<#if object.attributes.html[0]??>
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;
</#if>
<#list doc["/object/attributes/enum[@scope='global']"] as enum>
import ${object.package}.model.enums.${enum.@class};
</#list>

<#if object.attributes.set[0]?? || object.attributes.object[0]?? || object.attributes.html[0]?? || doc["/object/attributes/*[@lazy='true']"]??>
import redora.rdo.exceptions.*;
import ${object.package}.service.*;
</#if>
<#if object.attributes.set[0]??>
import redora.rdo.impl.*;
</#if>
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.text.ParseException;

import redora.rdo.api.*;
import redora.rdo.util.Constants;
import java.util.logging.Level;
import java.util.logging.Logger;
import ${object.package}.model.*;
import ${object.package}.model.fields.${object.name}Fields;

<#if object.description[0]??>
/** 
${object.description} 
*/
</#if>
public class ${object.name}Base implements Persistable<#if object.interface[0]??>, ${object.interface}</#if> {
  private Logger l = Logger.getLogger("${object.package}.model.${object.name}Base");
  
  public Long id;
  public Long getId() {
    return id;
  }
  public void setId(Long id) {
   if (this.id != null) throw new RuntimeException("It is not allowed to modify the id");
    this.id = id;
  }
  public Date creationDate;
  public Date getCreationDate() {
    return this.creationDate;
  }
  public Date updateDate;
  public Date getUpdateDate() {
    return this.updateDate;
  }
<#list object.attributes.enum as att>
  <#if !att.@scope[0]?? || att.@scope[0] == "local">
  <#if att.description[0]??>
  /** ${att.description} */
  </#if>
  public enum ${att.@class} {
  <#list att.element as value>
    <#if value.@description[0]??>
    /** ${value.@description} */
    </#if>
    ${value.@name}<#if value_has_next>,<#else>;</#if>
  </#list>
    /** @return Null, or the result of valueOf() */
    public static ${att.@class} valueOfNullSafe(String value) {
	  if (value != null)
		  return valueOf(value);
	  return null; 
    }
  }
  </#if>
</#list>

<#list object.attributes?children as att>
  <#if att?node_name != "set" && att?node_type == "element">
    <#if att?node_name == "xml">
  public ${att.@class[0]!att.@name?cap_first} ${att.@name};
  /** Reflection Hash, determined when ${att.@name} is retrieved from the database. When not yet retrieved, it's value equals -1 */
  public int dirty${att.@name?cap_first}Hash = -1;
    <#elseif att?node_name == "date" || att?node_name == "datetime">
  public Date ${att.@name};
    <#elseif att?node_name == "enum">
  public ${att.@class} ${att.@class?uncap_first};
    <#elseif att?node_name == "object">
  public ${att.@class} ${att.@class?uncap_first};
  public Long ${att.@class?uncap_first}Id;
    <#elseif att?node_name == "html" || att?node_name == "string">
  public String ${att.@name};
    <#elseif att?node_name == "boolean">
  public Boolean ${att.@name};
    <#else>
  public ${att?node_name?cap_first} ${att.@name};
    </#if>
  </#if>
</#list>

<#list object.attributes.set as att>
  <#if !att.@multiplicity[0]?? || att.@multiplicity=="n-to-1">
  private PersistableSet<${att.@class}> <#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if> = new PersistableHashSet<${att.@class}>();
  <#else>
  private PersistableNtoMSet<${att.@class}> <#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if> = new PersistableNtoMHashSet<${att.@class}>();
  </#if>
</#list>

  public Set<${object.name}Fields> dirty = new HashSet<${object.name}Fields>();
  public boolean isNew = true;

  /**
  * This method will set default values for:<br>
<#list object.attributes?children as att>
  <#if att.default[0]??>
  * ${att.@name!att.@class} - ${att.@default};<br>
  </#if>
</#list>
  */
  public ${object.name}Base() {
    super();
<#list object.attributes?children as att>
  <#if att.@default[0]??>
    <#if att?node_name == "boolean">
    set${att.@name?cap_first}(Boolean.<#if att.@default == "true">TRUE<#else>FALSE</#if>);
    <#elseif att?node_name == "string">
    set${att.@name?cap_first}("${att.@default}");
    <#elseif att?node_name == "integer" || att?node_name == "long">
    set${att.@name?cap_first}(${att.@default});
    <#elseif att?node_name == "enum">
    set${att.@class}(${att.@class}.${att.@default});
    <#else>
    error - undefined default ${att?node_name}
    </#if>
  </#if>
</#list>
  }

<#list object.attributes?children as att>
 <#if att?node_name != "set" && att?node_type == "element">
  <#if att.description[0]??>
  /** ${att.description} **/
  </#if>
  <#if att?node_name == "boolean">
  public void set${att.@name?cap_first}(Boolean ${att.@name}) {
    if (${att.@name} != this.${att.@name})
      dirty.add(${object.name}Fields.${att.@name});
    this.${att.@name} = ${att.@name};
  }
  <#elseif att?node_name == "date" || att?node_name == "datetime">
  public void set${att.@name?cap_first}(Date ${att.@name}) {
    String stripped = null;
    //strip (nano) seconds - hours to ${att?node_name} level
    if (${att.@name} != null) {
      stripped = Constants.${att?node_name?upper_case}.format(${att.@name});
    }
    if ((this.${att.@name} == null ? null : Constants.${att?node_name?upper_case}.format(this.${att.@name})) != stripped) {
      dirty.add(${object.name}Fields.${att.@name});
      if (stripped == null) {
        this.${att.@name} = null;
      } else {
        try {
          this.${att.@name} = Constants.${att?node_name?upper_case}.parse(stripped);
        } catch (ParseException e) {
          l.log(Level.SEVERE, "Did not expect this would not parse to date " + stripped, e);
          throw new RuntimeException("Did not expect this would not parse to date " + stripped, e);
        }
      }
    }
  }
  <#elseif att?node_name == "xml">
  public void set${att.@name?cap_first}(${att.@class[0]!att.@name?cap_first} ${att.@name}) {
	//No need for any dirty setting, this is done just before persisting using dirty${att.@name?cap_first}Hash.
    this.${att.@name} = ${att.@name};
  }
  <#elseif att?node_name == "object">
  public void set${att.@class}(${att.@class} ${att.@class?uncap_first}) throws LazyException {
     //The ${att.@class} field is lazy loaded, first invoke the getter:
    if (this.${att.@class?uncap_first} == null)
  	  get${att.@class}();
    
    if (${att.@class?uncap_first} != this.${att.@class?uncap_first})
      dirty.add(${object.name}Fields.${att.@class?uncap_first}Id);
    this.${att.@class?uncap_first} = ${att.@class?uncap_first};
    if (this.${att.@class?uncap_first} != null)
      this.${att.@class?uncap_first}Id = ${att.@class?uncap_first}.getId();
    else
      this.${att.@class?uncap_first}Id = null;
  }
  
  public void set${att.@class}Id(Long ${att.@class?uncap_first}Id) {
    if (${att.@class?uncap_first}Id != this.${att.@class?uncap_first}Id)
      dirty.add(${object.name}Fields.${att.@class?uncap_first}Id);
    this.${att.@class?uncap_first}Id = ${att.@class?uncap_first}Id;
  }
  <#elseif att?node_name == "enum">
  public void set${att.@class}(${att.@class} ${att.@class?uncap_first}) {
    if (${att.@class?uncap_first} != this.${att.@class?uncap_first})
      dirty.add(${object.name}Fields.${att.@class?uncap_first});
    this.${att.@class?uncap_first} = ${att.@class?uncap_first};
  }
  <#elseif att?node_name == "html">
  public void set${att.@name?cap_first}(String ${att.@name}) {
    if (${att.@name} != null) {
      Policy policy = Policy.getInstance(Policy.class.getResourceAsStream("/${att.@policy[0]!"antisamy.xml"}"));
      AntiSamy as = new AntiSamy();
      policy.setDirective(Policy.MAX_INPUT_SIZE, "100000"); //assuming a max size of 65k
      CleanResults cr = as.scan(${att.@name}, policy);
      for (Object error : cr.getErrorMessages()) {
        l.log(Level.INFO, "Message in html handling for ${att.@name}. " + error);
      }

      if (cr.getCleanHTML() != this.${att.@name}) {
        this.${att.@name} = ${att.@name};
        dirty.add(${object.name}Fields.${att.@name});
      }
    } else if (this.${att.@name} != null) {
      this.${att.@name} == null;
      dirty.add(${object.name}Fields.${att.@name});
    }
  }
  <#else>
  public void set${att.@name?cap_first}(${att?node_name?cap_first} ${att.@name}) <#if att.@lazy[0]?? && att.@lazy == "true">throws LazyException </#if>{
    <#if att.@lazy[0]?? && att.@lazy == "true">
     //The ${att.@name} field is lazy loaded, first invoke the getter:
    if (this.${att.@name} == null)
  	  get${att.@name?cap_first}();
    </#if>
    if (${att.@name} != this.${att.@name})
      dirty.add(${object.name}Fields.${att.@name});
    this.${att.@name[0]!att.@class?uncap_first} = ${att.@name};
  }
  </#if>

  <#if att.description[0]??>
  /** ${att.description} **/
  </#if>
  <#if att.@lazy[0]?? && att.@lazy == "true">
  	<#if att?node_name = "string">
  public String get${att.@name?cap_first}() throws LazyException {
  	if (${att.@name} == null && this.id != null) {
  	  try {
	    ${att.@name} = ServiceFactory.${object.name?uncap_first}Service().find${att.@name?cap_first}ById(id);
      } catch (PersistenceException e) {
        throw new LazyException("Failed to lazily retrieve ${att.@name} for ${object.name} with id: " + id, e);
      }
    }
    return ${att.@name?uncap_first};
  }		
  	</#if>
  <#else>
    <#if att?node_name == "boolean">
  public Boolean get${att.@name?cap_first}() {
    <#elseif att?node_name == "date" || att?node_name == "datetime">
  public Date get${att.@name?cap_first}() {
    <#elseif att?node_name == "xml">
  public ${att.@class[0]!att.@name?cap_first} get${att.@name?cap_first}() throws LazyException {
    if (${att.@name} == null) {
    	if (dirty${att.@name?cap_first}Hash == -1 && id != null)
    		try {
	    		${att.@name} = ServiceFactory.${object.name?uncap_first}Service().find${att.@name?cap_first}ById(id);
 			} catch (PersistenceException e) {
				throw new LazyException("Failed to lazily retrieve ${att.@name} for ${object.name} with id: " + id, e);
			}
    	else
    		${att.@name} = new ${att.@class[0]!att.@name?cap_first}();
    	if (${att.@name} != null)
	    	dirty${att.@name?cap_first}Hash = HashCodeBuilder.reflectionHashCode(${att.@name});
	    else
	    	dirty${att.@name?cap_first}Hash = 0;
    }
    <#elseif att?node_name == "enum">
  public ${att.@class} get${att.@class}() {
    <#elseif att?node_name == "object">
  public ${att.@class} get${att.@class}() throws LazyException {
    <#else>
  public ${att?node_name?cap_first} get${att.@name?cap_first}() {
    </#if>
    <#if att?node_name == "object">
  	if (${att.@class?uncap_first} == null && ${att.@class?uncap_first}Id != null) {
  		try {
	  		${att.@class?uncap_first} = ServiceFactory.${att.@class?uncap_first}Service().findById(this.${att.@class?uncap_first}Id);
		} catch (PersistenceException e) {
			throw new LazyException("Failed to lazily retrieve ${att.@class} for ${object.name} with id: " + id, e);
		}
  	}
  	return ${att.@class?uncap_first};
  }
  public Long get${att.@class}Id() {
  	return ${att.@class?uncap_first}Id;
  }
    <#else>
    return ${att.@name[0]!att.@class?uncap_first};
  }
    </#if>
 </#if> 
 </#if>
</#list>

<#list object.attributes.set as att>
  /**
  <#if att.description[0]??>
  * ${att.description}
  </#if>
  * <br />
  * If you wish to add a ${att.@class} to this list, do something like: get${att.@class}s().add(${att.@class});.
  * All the Collection methods like add, remove, addAll and removeAll are supported.
  * When you add or update ${att.@class}s to this set, they will be persisted together with ${object.name}.
  * @return Empty or filled list.
  */
  <#if !att.@multiplicity[0]?? || att.@multiplicity=="n-to-1">
  public PersistableSet<${att.@class}> get<#if att.@plural[0]??>${att.@plural?cap_first}<#else>${att.@class}s</#if>()
  <#else>
  public PersistableNtoMSet<${att.@class}> get<#if att.@plural[0]??>${att.@plural?cap_first}<#else>${att.@class}s</#if>()
  </#if>
    throws ConnectException, QueryException, CopyException {
    if (!<#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if>.isRetrieved() && !isNew) {
      <#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if>.setRetrieved(true);
      <#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if>.addAll(ServiceFactory.${att.@class?uncap_first}Service().findBy${object.name}Id(id));
    }

    return <#if att.@plural[0]??>${att.@plural}<#else>${att.@class?lower_case}s</#if>;
  }
</#list>
	
	/**
	* Checks if any of the attributes have changed. Related children are not checked.
	* <#if object.attributes.xml[0]??>Changes in the XML document are found using reflection on the document.</#if>
	* @return true if any of the attributes of ${object.name} have changed
	*/
	public boolean isDirty() {
	<#list object.attributes.xml as att>
		//JAXB XML documents cannot be compared using .equals. The XML document has to be compared element by element.
		//Reflection is used to compare two XML documents. When ${att.@name} is retrieved from storage, the old${att.@name?cap_first}Hash is set.
		//So, to see if the XML document is changed compare it with the current hash.
		if (dirty${att.@name?cap_first}Hash != -1 || ${att.@name} != null) { //Meaning: ${att.@name} is retrieved from storage or has been initialized
			try {
				int new${att.@name?cap_first}Hash = HashCodeBuilder.reflectionHashCode(get${att.@name?cap_first}());
				if ((get${att.@name?cap_first}() == null && dirty${att.@name?cap_first}Hash != 0) || (get${att.@name?cap_first}() != null && new${att.@name?cap_first}Hash != dirty${att.@name?cap_first}Hash)) {
					dirty.add(${object.name}Fields.${att.@name});
					if (get${att.@name?cap_first}() == null)
						dirty${att.@name?cap_first}Hash = 0;
					else
						dirty${att.@name?cap_first}Hash = new${att.@name?cap_first}Hash;
				}
			} catch (PersistenceException e) {}
		}
	</#list>
	
		return dirty.size() != 0;
 	}
	
	/** 
	* Persistence Layer's method, so you will probably will not need to use this method. 
	* Sets this ${object.name} as if everything is
	* persisted. Any related objects and children are left unchanged.
	*/
  public void clean() {
    dirty = new HashSet<${object.name}Fields>();
  }

  public boolean equals(${object.name} o) {
    if (getId() != null)
      return getId().equals(o.getId());
    return false;
  }
}
